#!/usr/bin/python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = [u'GuiProcess']

import sys
import warnings


from pyLot.core import (ENCODING, check_type, hardbook, get_data)
from pyLot.interfaces import  WriterInterface

from _pylot.qtgui.tools import generate_pyfile_from_uifile
from _pylot.qtgui.interfaces.widgetinterface import WidgetInterface
from _pylot.qtgui.widgets.gui_textview  import GuiTextView

from Qt4 import QtGui
from Qt4.QtCore import (SIGNAL, QMutex)

generate_pyfile_from_uifile(__name__,
  src=hardbook(u'uifiles', u'process.ui'),
  dest=get_data(__name__, u'_gui_process.py'))

from _gui_process import Ui_GuiProcess
class GuiProcess(QtGui.QWidget, Ui_GuiProcess, WidgetInterface):
  u"""
  GuiProcess provides a widget used to display process outputs.
  The widget is split into two views for standard and error outputs.
  """
  def __init__(self, stdout=None, stderr=None):
    u"""
    :param io_handler: An IOHandler
    :type io_handler: :class:`~_pylot.interface.iohandler.IOHandlerInterface`
    :param formats: a dict of QTextCharFormat
    :type formats: obj:`dict`
    """
    QtGui.QWidget.__init__(self)
    WidgetInterface.__init__(self)
    self.running = False
    self.setupUi(self)

    if stdout is None :
      stdout = GuiTextView()
    else :
      check_type(u'stdout', stdout, WriterInterface)
    if stderr is None :
      stderr = GuiTextView()
    else :
      check_type(u'stderr', stderr, WriterInterface)

    self._stdout = stdout
    self._stderr = stderr

    self.layout_stdout.addWidget(self._stdout)
    self.append(self._stdout)

    self.layout_stderr.addWidget(self._stderr)
    self.append(self._stderr)

    self.splitter_moved = False

    self.command = None
    self.command_group = None
    self.process = None

    self._auto_scroll_output = True
    self._auto_scroll_error = True

    self.connect(self.splitter, SIGNAL('splitterMoved(int,int)'),
                 self._onSplitterSplitterMoved)

  _lock_process = QMutex()

  def _getrunning (self):
    self._lock_process.lock()
    value = self._running
    self._lock_process.unlock()
    return value

  def _setrunning(self, value):
    self._lock_process.lock()
    self._running = value
    self._lock_process.unlock()

  running = property(fget=_getrunning, fset=_setrunning)
  stdout = property(fget=lambda self:self._stdout)
  stderr = property(fget=lambda self:self._stderr)

  def setSplitterState (self, state):
    u"""
    :param state: a splitter state (QByteArray given by QSplitter.saveState for example)
    :type state: QByteArray
    """
    self.splitter.restoreState(state)

  def getSplitterState (self):
    return self.splitter.saveState()

  def writeBoth (self, text, style=u'std'):
    self.writeStdout(text, style)
    self.writeStderr(text, style)

  def writeStdout (self, text, style=u'std'):
    self._stdout.write(text, style)

  def writeStderr (self, text, style=u'std'):
    self._stderr.write(text, style)

  def _onSplitterSplitterMoved (self, pos, idx):
    self.splitter_moved = True

  def _updateOutText(self):
    t = str(self.process.readAllStandardOutput()).decode(ENCODING, u'replace')

    if u'write' in self.stdout_mode :
      self.writeStdout(t)

    if u'save' in self.stdout_mode :
      self.command.stdout += t

    if self._auto_scroll_output is True :
      self._stdout.lockView()
    else :
      self._stdout.lockView(False)

  def _updateErrText(self):
    t = str(self.process.readAllStandardError()).decode(ENCODING, u'replace')

    if u'write' in self.stderr_mode :
      self.writeStderr(t)

    if u'save' in self.stderr_mode :
      self.command.stderr += t

    if self._auto_scroll_error is True :
      self._stderr.lockView()
    else :
      self._stderr.lockView(False)

  def connectProcess (self, command_group, command, process_handler):
    self.running = True
    self.command_group = command_group
    self.process = command.thread.thread
    self.command = command

    if self.command_group.stdout_mode is None :
      self.stdout_mode = process_handler.stdout_mode
    else :
      self.stdout_mode = self.command_group.stdout_mode

    if self.command_group.stderr_mode is None :
      self.stderr_mode = process_handler.stderr_mode
    else :
      self.stderr_mode = self.command_group.stderr_mode

    if u'save' in self.stdout_mode :
      self.command.stdout = u''
    else :
      self.command.stdout = None
    if u'save' in self.stderr_mode :
      self.command.stderr = u''
    else :
      self.command.stderr = None

    self.stdout_writers = [self._stdout]
    self.stdout_writers += self.command_group.stdout_writers
    self.stderr_writers = [self._stderr]
    self.stderr_writers += self.command_group.stderr_writers

    self.connect(self.process, SIGNAL("readyReadStandardOutput()"),
                   self._updateOutText)
    self.connect(self.process, SIGNAL("readyReadStandardError()"),
                   self._updateErrText)

  def disconnectProcess (self, command_group):
    # Reset process variables
    self.command = None
    self.command_group = None
    self.process = None

    self.stdout_writers = [self._stdout]
    self.stderr_writers = [self._stderr]

    self.running = False


  def lockView (self, boolean):
    self._auto_scroll_error = boolean
    self._auto_scroll_output = boolean

  def changeBackgroundColor (self, text_edit=None,
                             color=QtGui.QColor(255, 255, 255)):
    if text_edit is None :
      text_edit = [self._stdout, self._stderr]

    for widget in text_edit :
      widget.changeBackgroundColor(color)

  def clearOutput (self):
    self._stdout.clear()

  def clearError (self):
    self._stderr.clear()

  def cancelProcess (self):
    command_group = self.command_group
    #self.controller.cancelProcess(self, self.command_group)
    if command_group :
      for cmd in command_group.cmds :
        cmd.kill()
      self.writeBoth(tr_(u'\nprocess aborted'), u'warn')


def main(args):
  app = QtGui.QApplication(args)
  win = QtGui.QMainWindow()

  widget = GuiProcess()
  win.setCentralWidget(widget)
  for tool_bar in widget.tool_bars :
    win.addToolBar(tool_bar)
  for menu in widget.menus :
    win.menu_bar.addMenu(menu)

  if widget.pref :
    widget.pref.show()

  widget.writeBoth(u'both: salut \n', u'title')
  widget.writeStdout(u'std: ¡ ça marche ! συγχαρητήρια ! 祝賀 !', u'warn')
  widget.writeStderr(u'err: ¡ ça marche ! συγχαρητήρια ! 祝賀 !', u'info')

  win.show()

  return app.exec_()

if __name__ == u"__main__":
  main(sys.argv)
  import doctest
  doctest.testmod()
